button: Track gesture point to maintain priv->in_button
authorCarlos Garnacho <carlosg@gnome.org>
Wed, 20 Aug 2014 18:12:35 +0000 (20:12 +0200)
committerCarlos Garnacho <carlosg@gnome.org>
Tue, 26 Aug 2014 21:21:24 +0000 (23:21 +0200)
This makes the active state work invariably with both mouse/touch, and
regardless of X11 pointer emulation being friendly and sending crossing
events for the emulated pointer events in the latter.

This makes GtkButtons' active state look correct when pressing on
touchscreens on wayland.

https://bugzilla.gnome.org/show_bug.cgi?id=731380

gtk/gtkbutton.c

index c1f4d0d0f4e91193612c22c0f0114aa8747bfde5..9c1dcb441ce36e9882b82aaa941654bbd89ed80c 100644 (file)
@@ -592,6 +592,7 @@ multipress_pressed_cb (GtkGestureMultiPress *gesture,
   if (priv->focus_on_click && !gtk_widget_has_focus (widget))
     gtk_widget_grab_focus (widget);
 
+  priv->in_button = TRUE;
   g_signal_emit (button, button_signals[PRESSED], 0);
   gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
 }
@@ -604,10 +605,44 @@ multipress_released_cb (GtkGestureMultiPress *gesture,
                         GtkWidget            *widget)
 {
   GtkButton *button = GTK_BUTTON (widget);
+  GtkButtonPrivate *priv = button->priv;
+  GdkEventSequence *sequence;
+  GdkDevice *source;
+
+  sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
+  source = gdk_event_get_source_device (gtk_gesture_get_last_event (GTK_GESTURE (gesture),
+                                                                    sequence));
+  if (gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN)
+    priv->in_button = FALSE;
 
   g_signal_emit (button, button_signals[RELEASED], 0);
 }
 
+static void
+multipress_gesture_update_cb (GtkGesture       *gesture,
+                              GdkEventSequence *sequence,
+                              GtkButton        *button)
+{
+  GtkButtonPrivate *priv = button->priv;
+  GtkAllocation allocation;
+  gboolean in_button;
+  gdouble x, y;
+
+  if (sequence != gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture)))
+    return;
+
+  gtk_widget_get_allocation (GTK_WIDGET (button), &allocation);
+  gtk_gesture_get_point (gesture, sequence, &x, &y);
+
+  in_button = (x >= 0 && y >= 0 && x < allocation.width && y < allocation.height);
+
+  if (priv->in_button != in_button)
+    {
+      priv->in_button = in_button;
+      gtk_button_update_state (button);
+    }
+}
+
 static void
 gtk_button_init (GtkButton *button)
 {
@@ -646,6 +681,7 @@ gtk_button_init (GtkButton *button)
   gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->gesture), GDK_BUTTON_PRIMARY);
   g_signal_connect (priv->gesture, "pressed", G_CALLBACK (multipress_pressed_cb), button);
   g_signal_connect (priv->gesture, "released", G_CALLBACK (multipress_released_cb), button);
+  g_signal_connect (priv->gesture, "update", G_CALLBACK (multipress_gesture_update_cb), button);
   gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (priv->gesture), GTK_PHASE_BUBBLE);
 }